	.text
/**
 * svc异常处理函数
 * os_task_switch_to(ctx)
 */
	.global SVC_Handler
	.type SVC_Handler, %function
SVC_Handler:
    // 恢复r4-r11
    ldmia r0!, {r4-r11}
    
	// 切换栈PSP指向新的空间
    ldr r0, [r0]        // 加载r13
	msr psp, r0
   
    // 重设MSP
    ldr r0, =0xE000ED08
    ldr r0, [r0]    // 取VTOR寄存器内容
    ldr r0, [r0]    // 取SP值
    msr msp, r0
    
	// bx 0xFFFFFFFD, use psp, thread mode, fpu not used
    // 这里恢复时会从栈里弹出r0-r3等寄存器
	ldr r0, =0xFFFFFFFD    
	BX  r0

/**
 * 采用软中断触发上下文切换，主要用于中断处理中
 * 无需关中断，因为中断嵌套已经被关闭
 */
    .global PendSV_Handler
	.extern os_sched_switch_ctx, int_ctx_from
	.type PendSV_Handler, %function
PendSV_Handler:
	// 注意关掉中断，以免发生异常现像
	cpsid   I 

    // 保存浮点s16-s31到当前栈
    mrs r1, psp
    ands r2, lr, #(1 << 4)   // 保存FPU使用状态, 0-使用FPU，1-未使用FPU
    tst r2, #(1 << 4)   
    bne skip_save_vfp
    vstmdb r1!,{s16-s31}  //  保存VFP

    // 读取当前任务的ctx位置
skip_save_vfp:
	ldr r0, =int_ctx_from			
    ldr r0, [r0]
    
	// 保存r4-r11
	stmia r0!, {r4-r11}

    // 保存PSP
    stmia r0!, {r1}

    // 保存flags
    stmia r0!, {r2}

    bl os_sched_switch_ctx
    
    // 读取下一任务的ctx位置
	ldr r0, =int_ctx_to			
    ldr r0, [r0]

    // 恢复r4-r11
    ldmia r0!, {r4-r11}

	// 切换栈PSP指向新的空间
    ldmia r0!, {r1}

    // 读取flags
    ldmia r0!, {r2}

    // 恢复浮点s16-s31
    cbnz r2, skip_restore_vfp
    vldmia r1!, {s16-s31}    

skip_restore_vfp:
    // 恢复PSP
    msr psp, r1

	// bx 0xFFFFFFFD, use psp, thread mode
    // 这里恢复时会从栈里弹出r0-r3等寄存器
	ldr r0, =0xFFFFFFED   
    orr r0, r0, r2      // 将保存的状态与r2相与，来获得sp使用状态 
    cpsie i
	BX  r0
